#include "modbus_master.h"

#define READSTARTADDR 40030


Modbus_Master::Modbus_Master(int slave_id, QObject *parent) : QObject(parent)
{
    //qDebug() << "Modbus_Master Thread" << QThread::currentThreadId();
    m_slave_id = slave_id;        //从机ID
    is_work = false;             //modbus是否连接成功
    m_master_thread = new QThread();
    this->moveToThread(m_master_thread);
    connect(m_master_thread,SIGNAL(started()),this,SLOT(open_poll_thread()));
    connect(m_master_thread,SIGNAL(finished()),this,SLOT(close_poll_thread()));
    m_master_thread->start();
}

Modbus_Master::~Modbus_Master()
{
    m_master_thread->quit();
    m_master_thread->wait();
    //qDebug() << "~Modbus_Master" << QThread::currentThreadId();
}

void Modbus_Master::open_poll_thread()
{
    //qDebug() << "initPollThread" << QThread::currentThreadId();
    timer_one = new QTimer();
    timer_one->stop();
    connect(timer_one,&QTimer::timeout,this,&Modbus_Master::modbus_master_poll_process);                //modbus从机数据扫描时钟
}

void Modbus_Master::close_poll_thread()
{
    //qDebug() << "ClosePollThread" << QThread::currentThreadId();
    timer_one->stop();
    delete timer_one;
    if(is_work)
    {
        modbus_close(m_modbus);
        modbus_free(m_modbus);
    }
}
uint16_t modbus_hold_reg[100];      //缓存读取到的数据
void Modbus_Master::modbus_update_text()
{
    int readNum = 6;
    modbus_set_slave(m_modbus,m_slave_id);//设置需要连接的从机地址

    int ret = modbus_read_registers(m_modbus,40030,readNum,modbus_hold_reg);            //读取保持寄存器的第0位开始的前5位
    //modbus_read_input_registers(m_modbus,0,50,modbus_input_reg);   //读取输入寄存器的第0位开始的前5位
    QString err;
    if(ret != readNum)      //读取错误
    {
        if( ret < 0 )
        {
            if(errno == EIO)
            {
                err += tr( "I/O error" );
                err += ": ";
                err += tr( "did not receive any data from slave." );
            }
            else
            {
                err += tr( "Protocol error" );
                err += ": ";
                err += tr( "Slave threw exception '" );
                err += modbus_strerror( errno );
                err += tr( "' or function not implemented." );
            }
        }
        else
        {
            err += tr( "Protocol error" );
            err += ": ";
            err += tr( "Number of registers returned does not "
                    "match number of registers requested!" );
        }
    }

    if( err.size() > 0 )
            emit signal_send_slave_info("读取失败:" + err);
    else        //读取正常
    {
        QString info = QString("小区编号：%1，房屋编号：%2，电表编号：%3，电表状态：%4，总耗电量：%5，总有功功率：%6 \r\n ")\
                .arg(QString::number(m_slave_id)).arg(modbus_hold_reg[1])\
             .arg(modbus_hold_reg[2]).arg(modbus_hold_reg[3])\
             .arg(modbus_hold_reg[4]).arg(modbus_hold_reg[5]);

        emit signal_send_slave_info(info);
    }
}

void Modbus_Master::modbus_master_poll_process()
{
    modbus_update_text();
}

void Modbus_Master::connect_modbus_master(QString port_name, int baudrate)
{
    qDebug() << "connect_modbus_master" << QThread::currentThreadId();
    m_modbus = modbus_new_rtu(port_name.toLatin1().data(),baudrate,'N',8,1);   //无法验证串口端口是否被占用
    modbus_set_slave(m_modbus,m_slave_id);                    //设置从机地址为1
    modbus_connect(m_modbus);

    //寄存器map初始化
    mb_mapping = modbus_mapping_new(READSTARTADDR, READSTARTADDR,READSTARTADDR, READSTARTADDR); //依次设置 bits、input_bits、registers、input_registers寄存器的大小，他们默认起始地址均为0
    if (mb_mapping == NULL) {
        qDebug() << "connect fail" << "Failed to allocate the mapping: " << QString(modbus_strerror(errno));
        modbus_free(m_modbus);
        return;
    }

    modbus_register_monitor_add_item_fnc(m_modbus, Modbus_Master::modbus_monitor_add_item);
    //modbus_register_monitor_raw_data_fnc(m_modbus, Modbus_Master::stBusMonitorRawData);
    timer_one->start(1000);
    is_work = true;
}

void Modbus_Master::disconnect_modbus_master()
{
    qDebug() << "disconnect_modbus_master" << QThread::currentThreadId();
    timer_one->stop();
    modbus_close(m_modbus);
    modbus_free(m_modbus);
    is_work = false;
}


//modbus回调函数
void Modbus_Master::modbus_monitor_add_item( modbus_t * modbus, uint8_t is_request, uint8_t slave, uint8_t func, uint16_t addr, uint16_t nb, uint16_t expected_crc, uint16_t actual_crc )
{
    Q_UNUSED(modbus);
    qDebug() << "成功接受到从机回复" << "isRequest" << is_request << "slave" << slave << "func" << func\
             << "addr" << addr << "nb" << nb << "expectedCRC" << expected_crc  << "actualCRC" << actual_crc;
}

// 送成功/接受成功会到此回掉函数
void Modbus_Master::modbus_monitor_raw_data( modbus_t * modbus, uint8_t * data, uint8_t dataLen, uint8_t add_new_line , uint8_t direction)
{
    Q_UNUSED(modbus);
    Q_UNUSED(add_new_line);
    Q_UNUSED(direction);
    QString dump;
    for( int i = 0; i < dataLen; ++i )
    {
        dump += QString::asprintf( "%.2x ", data[i] );
    }
    //    if(direction == 0)
    //        qDebug() << "串口发送"  << "data" << dump;
    //    else
    //        qDebug() << "串口接受" << "data" << dump;
}
